/*!
 * \file build_sparse_constraints_visitor_test.cc
 *
 * \brief Build sparse constraints visitor tests
 *
 * \date Started: 6/8/2010
 * \date Last Modified: 6/8/2010
 * \authors Alan LaMielle
 *
 * Copyright (c) 2010, Colorado State University <br>
 * All rights reserved. <br>
 * See ../../COPYING for details. <br>
 */

#include <iegenlib/iegenlib.h>

#include <gtest/gtest.h>

using iegenlib::IEGenLibContext;
using iegenlib::Set;
using iegenlib::Relation;
using iegenlib::Symbolic;
using iegenlib::PresSet;
using iegenlib::PresRelation;
using iegenlib::Conjunction;
using iegenlib::BuildSymTableVisitor;
using iegenlib::StringException;
using iegenlib::SymbolTable;
using iegenlib::BuildSparseConstraints;

//buildsparseconstraintstest first builds the symbol table then builds the
//sparse constraints. The current toString just prints the size of each expVec
//of each of the Expressions in the map. basically checking that all nodes are
//in the map that need to be in the map

#if 0
TEST(BuildSparseConstraintsTest, emptyTestsSet) {

   std::string temp="{[]}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, emptyTestsSet) {

   std::string temp="{[]}";
   Set PS(temp);

   EXPECT_EQ(PS.getBSCVstring(),"");
}

#if 0
TEST(BuildSparseConstraintsTest, VarTupTestsSet) {

   std::string temp="{[x,y]}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, VarTupTestsSet) {

   std::string temp="{[x,y]}";
   Set PS(temp);

   EXPECT_EQ(PS.getBSCVstring(),"(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, lotsVarTupTestsSet) {

   std::string temp="{[u,v,w,x,y,z]}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(u)(v)(w)(x)(y)(z)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, lotsVarTupTestsSet) {

   std::string temp="{[u,v,w,x,y,z]}";
   Set PS(temp);

   EXPECT_EQ(PS.getBSCVstring(),"(u)(v)(w)(x)(y)(z)");
}

#if 0
TEST(BuildSparseConstraintsTest, varTupTestsWithconstraintsSet) {

   std::string temp="{[x,y,z]:x<y}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(-x+y-1)(x)(y)(z)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, varTupTestsWithconstraintsSet) {

   std::string temp="{[x,y,z]:x<y}";
   Set PS(temp);

   EXPECT_EQ(PS.getBSCVstring(),"(-x+y-1)(x)(y)(z)");
}

#if 0
TEST(BuildSparseConstraintsTest, symConstPassedinTestsSet) {

   std::string temp="{[x,y]:x<S}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   l1.push_back("S");
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(S-x-1)(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, symConstPassedinTestsSet) {

   std::string temp="{[x,y]:x<S}";
   Set PS(temp);

   EXPECT_EQ(PS.getBSCVstring(),"(-x+S-1)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, symConstNotPassedinTestsSet) {

   std::string temp="{[x,y]:x<S}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(-x+S-1)(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, symConstNotPassedinTestsSet) {

   std::string temp="{[x,y]:x<S}";
   Set PS(temp);

   EXPECT_EQ(PS.getBSCVstring(),"(-x+S-1)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, functionTestsNoSymconstPassedSet) {

   std::string temp="{[x,y]:x<f(S)}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(x)(y)(f(S))");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, functionTestsNoSymconstPassedSet) {

   std::string temp="{[x,y]:x<f(S)}";
   Set PS(temp);

   EXPECT_EQ(PS.getBSCVstring(),"(-x+f(S)-1)(S)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, functionTestsSymconstPassedSet) {

   std::string temp="{[x,y]:x<f(S)}";

   PresSet *PS = pres_parser::parse_set(temp);
   list<string> l1;
   l1.push_back("S");
   BuildSymTableVisitor stv(l1);
   PS->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PS->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(x)(y)(f(S))");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, functionTestsSymconstPassedSet) {

   std::string temp="{[x,y]:x<f(S)}";
   IEGenLibContext context;
   context.addSymbolic(Symbolic("S"));
   Set PS(temp, context);

   EXPECT_EQ(PS.getBSCVstring(),"(-x+f(S)-1)(S)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, emptyTestsRel) {

   std::string temp="{[]->[]}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, emptyTestsRel) {

   std::string temp="{[]->[]}";
   Relation PR(temp);

   EXPECT_EQ(PR.getBSCVstring(),"");
}

#if 0
TEST(BuildSparseConstraintsTest, VarTupTestsRel) {

   std::string temp="{[x,y]->[y,x]}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, VarTupTestsRel) {

   std::string temp="{[x,y]->[y,x]}";
   Relation PR(temp);

   EXPECT_EQ(PR.getBSCVstring(),"(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, lotsVarTupTestsRel) {

   std::string temp="{[u,v,w,x,y,z]->[y,x,x,x,x,y]}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(u)(v)(w)(x)(x1)(x2)(x3)(x4)(y)(y1)(y2)(z)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, lotsVarTupTestsRel) {

   std::string temp="{[u,v,w,x,y,z]->[y,x,x,x,x,y]}";
   Relation PR(temp);

   EXPECT_EQ(PR.getBSCVstring(),"(u)(v)(w)(x)(y)(z)");
}

#if 0
TEST(BuildSparseConstraintsTest, varTupTestsWithconstraintsRel) {

   std::string temp="{[x,y]->[y,x]:x<y}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, varTupTestsWithconstraintsRel) {

   std::string temp="{[x,y]->[y,x]:x<y}";
   Relation PR(temp);

   EXPECT_EQ(PR.getBSCVstring(),"(-x+y-1)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, symConstPassedinTestsRel) {

   std::string temp="{[x,y]->[y,x]:x<S}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   l1.push_back("S");
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(S)(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, symConstPassedinTestsRel) {

   std::string temp="{[x,y]->[y,x]:x<S}";
   IEGenLibContext context;
   context.addSymbolic(Symbolic("S"));
   Relation PR(temp,context);

   EXPECT_EQ(PR.getBSCVstring(),"(S-x-1)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, symConstNotPassedinTestsRel) {

   std::string temp="{[x,y]->[y,x]:x<S}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(S)(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, symConstNotPassedinTestsRel) {

   std::string temp="{[x,y]->[y,x]:x<S}";
   Relation PR(temp);

   EXPECT_EQ(PR.getBSCVstring(),"(-x+S-1)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, functionTestsNoSymconstPassedRel) {

   std::string temp="{[x,y]->[y,x]:x<f(S)}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(f(S))(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, functionTestsNoSymconstPassedRel) {

   std::string temp="{[x,y]->[y,x]:x<f(S)}";
   Relation PR(temp);

   EXPECT_EQ(PR.getBSCVstring(),"(-x+f(S)-1)(S)(x)(y)");
}

#if 0
TEST(BuildSparseConstraintsTest, functionTestsSymconstPassedRel) {

   std::string temp="{[x,y]->[y,x]:x<f(S,x,Z) and x<f(S,X,Z) and x<f(S,Z)}";

   PresRelation *PR = pres_parser::parse_relation(temp);
   list<string> l1;
   l1.push_back("S");
   BuildSymTableVisitor stv(l1);
   PR->apply(&stv);
   SymbolTable* mst = stv.getSymTable();

   BuildSparseConstraints bsc(stv.getSymTable(),stv.getMNumToDups());
   PR->apply(&bsc);

   EXPECT_EQ(bsc.toString(),"(f(S,x,Z))(f(S,X,Z))(f(S,Z))(x)(y)");
   delete mst;
}
#endif

TEST(BuildSparseConstraintsTest, functionTestsSymconstPassedRel) {

   std::string temp="{[x,y]->[y,x]:x<f(S,x,Z) and x<f(S,X,Z) and x<f(S,Z)}";
   Relation PR(temp);

   EXPECT_EQ(PR.getBSCVstring(),"(-x+f(S,X,Z)-1)(-x+f(S,Z)-1)(-x+f(S,x,Z)-1)(S)(X)(Z)(x)(y)");
}

TEST(BuildSparseConstraintsTest, SetException) {
     std::string temp="{[x,y]:x<S}";
     PresSet *PS = iegenlib::pres_parser::parse_set(temp);
     list<Conjunction*>const cnjj =  PS->getConjuncts();
     for(list<Conjunction*>::const_iterator itr =cnjj.begin() ; itr != cnjj.end(); itr++){
     set<string> l1;
     l1.insert("S");
     BuildSymTableVisitor stv(l1);
     (*itr)->apply(&stv);
     SymbolTable* mst = stv.getSymTable();

     BuildSparseConstraints bsc(mst, stv.getEqualities(), stv.getTuples());
     bool flag = false;
     try{
         PS->apply(&bsc);
     }
     catch(StringException err){
        flag = true;
     }

     if (!flag)
        {ADD_FAILURE()<<"BuildSparseConstraints Visitor exception not raised!";}
     }
     delete PS;
}

TEST(BuildSparseConstraintsTest, RelationException) {
    std::string temp="{[x,y]->[y,x]:x<S}";
    PresRelation *PR = iegenlib::pres_parser::parse_relation(temp);
    list<Conjunction*>const cnjj =  PR->getConjuncts();
    for(list<Conjunction*>::const_iterator itr =cnjj.begin() ; itr != cnjj.end(); itr++){
       set<string> l1;
       l1.insert("S");
       BuildSymTableVisitor stv(l1);
       (*itr)->apply(&stv);
       SymbolTable* mst = stv.getSymTable();
       BuildSparseConstraints bsc(mst, stv.getEqualities(), stv.getTuples());
    bool flag = false;
    try{
        PR->apply(&bsc);
    }
    catch(StringException err){
       flag = true;
    }

    if (!flag)
       {ADD_FAILURE()<<"BuildSparseConstraints Visitor exception not raised!";}
    }
    delete PR;
}
